#include "scene.h"
#include "opengl.h"
#include "goat3d.h"

using namespace goatgfx;

static Mesh *load_mesh(goat3d_mesh *gmesh);

Scene::~Scene()
{
	destroy();
}

void Scene::destroy()
{
	for(size_t i=0; i<objects.size(); i++) {
		delete objects[i];
	}
	objects.clear();

	for(size_t i=0; i<meshes.size(); i++) {
		delete meshes[i];
	}
	meshes.clear();

	for(size_t i=0; i<curves.size(); i++) {
		delete curves[i];
	}
	curves.clear();
}

bool Scene::load(const char *fname)
{
	goat3d *goat = goat3d_create();
	if(!goat) {
		return false;
	}
	if(goat3d_load(goat, fname) == -1) {
		goat3d_free(goat);
		return false;
	}

	// load all the meshes
	int num_meshes = goat3d_get_mesh_count(goat);
	for(int i=0; i<num_meshes; i++) {
		goat3d_mesh *gmesh = goat3d_get_mesh(goat, i);
		Mesh *mesh = load_mesh(gmesh);
		if(mesh) {
			meshes.push_back(mesh);
		}
	}

	// load all the nodes recursively
	int num_nodes = goat3d_get_node_count(goat);
	for(int i=0; i<num_nodes; i++) {
		goat3d_node *gnode = goat3d_get_node(goat, i);
	}

	goat3d_free(goat);
	return true;
}

bool Scene::save(const char *fname) const
{
	return false;	// TODO
}

void Scene::draw(long msec) const
{
	for(size_t i=0; i<objects.size(); i++) {
		objects[i]->draw(msec);
	}

	// if there are no objects in the scene, just draw the meshes instead
	if(objects.empty()) {
		for(size_t i=0; i<meshes.size(); i++) {
			meshes[i]->draw();
		}
	}
}

static Mesh *load_mesh(goat3d_mesh *gmesh)
{
	int nverts = goat3d_get_mesh_attrib_count(gmesh, GOAT3D_MESH_ATTR_VERTEX);
	float *data = (float*)goat3d_get_mesh_attribs(gmesh, GOAT3D_MESH_ATTR_VERTEX);

	if(!nverts || !data) {
		return 0;
	}
	int nfaces = goat3d_get_mesh_face_count(gmesh);

	Mesh *mesh = new Mesh;
	const char *name = goat3d_get_mesh_name(gmesh);
	if(name) {
		mesh->set_name(name);
	}

	mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, nverts, data);

	if((data = (float*)goat3d_get_mesh_attribs(gmesh, GOAT3D_MESH_ATTR_NORMAL))) {
		mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, nverts, data);
	}
	if((data = (float*)goat3d_get_mesh_attribs(gmesh, GOAT3D_MESH_ATTR_TANGENT))) {
		mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, nverts, data);
	}
	if((data = (float*)goat3d_get_mesh_attribs(gmesh, GOAT3D_MESH_ATTR_TEXCOORD))) {
		mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts, data);
	}
	if((data = (float*)goat3d_get_mesh_attribs(gmesh, GOAT3D_MESH_ATTR_COLOR))) {
		mesh->set_attrib_data(MESH_ATTR_COLOR, 4, nverts, data);
	}
	if((data = (float*)goat3d_get_mesh_attribs(gmesh, GOAT3D_MESH_ATTR_SKIN_WEIGHT))) {
		mesh->set_attrib_data(MESH_ATTR_BONEWEIGHTS, 4, nverts, data);
	}
	int *idata = (int*)goat3d_get_mesh_attribs(gmesh, GOAT3D_MESH_ATTR_SKIN_MATRIX);
	if(idata) {
		for(int i=0; i<nverts; i++) {
			mesh->set_attrib(MESH_ATTR_BONEIDX, i, Vector4(idata[0], idata[1], idata[2], idata[3]));
			idata += 4;
		}
	}

	if(nfaces && (idata = goat3d_get_mesh_faces(gmesh))) {
		mesh->set_index_data(nfaces * 3, (unsigned int*)idata);
	}
	return mesh;
}
